package me.ratel.demo.wechat.entities;

import com.google.common.hash.Hashing;
import me.ratel.demo.eBook.infrastructure.utils.XmlUtils;
import me.ratel.demo.wechat.utils.KeyValuePair;
import me.ratel.demo.wechat.utils.SignUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.nio.charset.Charset;
import java.util.Random;

/**
 * @author Administrator
 * @time 2016/8/7 17:00
 */
@XmlRootElement(name = "xml")
public class UnifiedOrderRequest {
    private static final Logger log = LoggerFactory.getLogger(UnifiedOrderRequest.class);

    // String(32)
    // 微信分配的公众账号ID（企业号corpid即为此appId）
    private String appId;

    // String(32)
    // 微信支付分配的商户号
    private String mchId;

    // 非必传
    // String(32)
    // 终端设备号(门店号或收银设备ID)，注意：PC网页或公众号内支付请传"WEB"
    private String deviceInfo;

    // String(32)
    // 随机字符串，不长于32位
    private String nonceStr;

    // String(32)
    // 签名
    private String sign;

    // String(128)
    // 商品简单描述，该字段须严格按照规范传递
    private String body;

    // String(6000)
    // 非必传
    // 商品详细列表，使用Json格式，传输签名前请务必使用CDATA标签将JSON文本串保护起来
    private String detail;

    // String(127)
    // 非必传
    // 附加数据，在查询API和支付通知中原样返回，该字段主要用于商户携带订单的自定义数据
    private String attach;

    // String(32)
    // 商户系统内部的订单号,32个字符内、可包含字母
    private String outTradeNo;

    // String(16)
    // 非必传
    // 符合ISO 4217标准的三位字母代码，默认人民币：CNY
    private String feeType;

    // Int
    // 订单总金额，单位为分
    private Integer totalFee;

    // String(16)
    // APP和网页支付提交用户端ip，Native支付填调用微信支付API的机器IP
    private String spbillCreateIP;

    // String(14)
    // 非必传
    // 订单生成时间，格式为yyyyMMddHHmmss，如2009年12月25日9点10分10秒表示为20091225091010
    private String timeStart;

    // String(14)
    // 非必传
    // 订单失效时间，格式为yyyyMMddHHmmss，如2009年12月27日9点10分10秒表示为20091227091010
    private String timeExpire;

    // String(32)
    // 非必传
    // 商品标记，代金券或立减优惠功能的参数
    private String goodsTag;

    // String(256)
    // 接收微信支付异步通知回调地址，通知url必须为直接可访问的url，不能携带参数。
    private String notifyUrl;

    // String(16)
    // 取值如下：JSAPI，NATIVE，APP
    private String tradeType;

    // String(32)
    // 非必传
    // trade_type=NATIVE，此参数必传。此id为二维码中包含的商品ID，商户自行定义。
    private String productId;

    // String(32)
    // 非必传
    // no_credit--指定不能使用信用卡支付
    private String noCredit;

    // String(128)
    // 非必传
    // trade_type=JSAPI，此参数必传，用户在商户appid下的唯一标识
    private String openid;

    // API密钥
    private String apiKey;

    private UnifiedOrderRequest() {
    }

    UnifiedOrderRequest(UnifiedOrderRequestBuilder builder) {
        setAppId(builder.getAppId());
        setMchId(builder.getMchId());

        setBody(builder.getBody());
//        setDetail(builder.getDetail());

        setNonceStr(Hashing.md5().hashString(
                String.valueOf(new Random().nextInt(10000)), Charset.forName("UTF-8")
        ).toString());

        setNotifyUrl(builder.getNotifyUrl());

        setOpenid(builder.getOpenid());
        setOutTradeNo(builder.getOutTradeNo());

        setSpbillCreateIP(builder.getSpbillCreateIP());

        setTotalFee(builder.getTotalFee());
        setTradeType(builder.getTradeType());

        setApiKey(builder.getApiKey());

        setSign(createSign());
    }

    private String createSign() {
        return SignUtil.sign(
                new KeyValuePair<>("key", getApiKey()),
                new KeyValuePair[]{
                        new KeyValuePair<>("openid", getOpenid()),
                        new KeyValuePair<>("body", getBody()),
                        new KeyValuePair<>("out_trade_no", getOutTradeNo()),
                        new KeyValuePair<>("total_fee", String.valueOf(getTotalFee())),
                        new KeyValuePair<>("notify_url", getNotifyUrl()),
                        new KeyValuePair<>("trade_type", getTradeType()),
                        new KeyValuePair<>("appid", getAppId()),
                        new KeyValuePair<>("mch_id", getMchId()),
                        new KeyValuePair<>("spbill_create_ip", getSpbillCreateIP()),
                        new KeyValuePair<>("nonce_str", getNonceStr())
                }
        );
    }

    @XmlElement(name = "appid")
    @XmlJavaTypeAdapter(value = AdaptorCDATA.class)
    public String getAppId() {
        return appId;
    }

    public void setAppId(String appId) {
        this.appId = appId;
    }

    public UnifiedOrderRequest setAppIdFluent(String appId) {
        setAppId(appId);
        return this;
    }

    @XmlElement(name = "attach")
    public String getAttach() {
        return attach;
    }

    public void setAttach(String attach) {
        this.attach = attach;
    }

    public UnifiedOrderRequest setAttachfluent(String attach) {
        setAttach(attach);
        return this;
    }

    @XmlElement(name = "body")
    @XmlJavaTypeAdapter(value = AdaptorCDATA.class)
    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }

    public UnifiedOrderRequest setBodyFluent(String body) {
        setBody(body);
        return this;
    }

    @XmlElement(name = "mch_id")
    @XmlJavaTypeAdapter(value = AdaptorCDATA.class)
    public String getMchId() {
        return mchId;
    }

    public void setMchId(String mchId) {
        this.mchId = mchId;
    }

    public UnifiedOrderRequest setMchIdFluent(String mchId) {
        setMchId(mchId);
        return this;
    }

    @XmlElement(name = "detail")
    public String getDetail() {
        return detail;
    }

    public void setDetail(String detail) {
        this.detail = detail;
    }

    public UnifiedOrderRequest setDetailFluent(String detail) {
        setDetail(detail);
        return this;
    }

    @XmlElement(name = "nonce_str")
    @XmlJavaTypeAdapter(value = AdaptorCDATA.class)
    public String getNonceStr() {
        return nonceStr;
    }

    public void setNonceStr(String nonceStr) {
        this.nonceStr = nonceStr;
    }

    public UnifiedOrderRequest setNonceStrFluent(String nonceStr) {
        setNonceStr(nonceStr);
        return this;
    }

    @XmlElement(name = "notify_url")
    @XmlJavaTypeAdapter(value = AdaptorCDATA.class)
    public String getNotifyUrl() {
        return notifyUrl;
    }

    public void setNotifyUrl(String notifyUrl) {
        this.notifyUrl = notifyUrl;
    }

    public UnifiedOrderRequest setNotifyUrlFluent(String notifyUrl) {
        setNotifyUrl(notifyUrl);
        return this;
    }

    @XmlElement(name = "openid")
    @XmlJavaTypeAdapter(value = AdaptorCDATA.class)
    public String getOpenid() {
        return openid;
    }

    public void setOpenid(String openid) {
        this.openid = openid;
    }

    public UnifiedOrderRequest setOpenidFluent(String openid) {
        setOpenid(openid);
        return this;
    }

    @XmlElement(name = "out_trade_no")
    @XmlJavaTypeAdapter(value = AdaptorCDATA.class)
    public String getOutTradeNo() {
        return outTradeNo;
    }

    public void setOutTradeNo(String outTradeNo) {
        this.outTradeNo = outTradeNo;
    }

    public UnifiedOrderRequest setOutTradeNoFluent(String outTradeNo) {
        setOutTradeNo(outTradeNo);
        return this;
    }

    @XmlElement(name = "device_info")
    public String getDeviceInfo() {
        return deviceInfo;
    }

    public void setDeviceInfo(String deviceInfo) {
        this.deviceInfo = deviceInfo;
    }

    @XmlElement(name = "fee_type")
    public String getFeeType() {
        return feeType;
    }

    public void setFeeType(String feeType) {
        this.feeType = feeType;
    }

    @XmlElement(name = "spbill_create_ip")
    @XmlJavaTypeAdapter(value = AdaptorCDATA.class)
    public String getSpbillCreateIP() {
        return spbillCreateIP;
    }

    public void setSpbillCreateIP(String spbillCreateIP) {
        this.spbillCreateIP = spbillCreateIP;
    }

    public UnifiedOrderRequest setSpbillCreateIPFluent(String spbillCreateIP) {
        setSpbillCreateIP(spbillCreateIP);
        return this;
    }

    @XmlElement(name = "time_start")
    public String getTimeStart() {
        return timeStart;
    }

    public void setTimeStart(String timeStart) {
        this.timeStart = timeStart;
    }

    @XmlElement(name = "time_expire")
    public String getTimeExpire() {
        return timeExpire;
    }

    public void setTimeExpire(String timeExpire) {
        this.timeExpire = timeExpire;
    }

    @XmlElement(name = "goods_tag")
    public String getGoodsTag() {
        return goodsTag;
    }

    public void setGoodsTag(String goodsTag) {
        this.goodsTag = goodsTag;
    }

    public void setTradeType(String tradeType) {
        this.tradeType = tradeType;
    }

    public UnifiedOrderRequest setTradeTypeFluent(String tradeType) {
        setTradeType(tradeType);
        return this;
    }

    @XmlElement(name = "product_id")
    public String getProductId() {
        return productId;
    }

    public void setProductId(String productId) {
        this.productId = productId;
    }

    @XmlElement(name = "limit_pay")
    public String getNoCredit() {
        return noCredit;
    }

    public void setNoCredit(String noCredit) {
        this.noCredit = noCredit;
    }

    @XmlElement(name = "total_fee")
    public Integer getTotalFee() {
        return totalFee;
    }

    public void setTotalFee(Integer totalFee) {
        this.totalFee = totalFee;
    }

    public UnifiedOrderRequest setTotalFeeFluent(Integer totalFee) {
        setTotalFee(totalFee);
        return this;
    }

    @XmlElement(name = "sign")
    @XmlJavaTypeAdapter(value = AdaptorCDATA.class)
    public String getSign() {
        return sign;
    }

    public void setSign(String sign) {
        this.sign = sign;
    }

    public UnifiedOrderRequest setSignFluent(String sign) {
        setSign(sign);
        return this;
    }

    @XmlTransient
    public String getApiKey() {
        return apiKey;
    }

    public void setApiKey(String apiKey) {
        this.apiKey = apiKey;
    }

    @XmlElement(name = "trade_type")
    @XmlJavaTypeAdapter(value = AdaptorCDATA.class)
    public String getTradeType() {
        return tradeType;
    }

    public String toXML() {
        return XmlUtils.toXML(this);
    }
}


